# Author: Kang Lin <kl222@126.com>

cmake_minimum_required(VERSION 3.21)
MESSAGE(STATUS "Found CMake ${CMAKE_VERSION}")

get_filename_component(RabbitCommonUtils_ROOT "${CMAKE_CURRENT_LIST_DIR}" ABSOLUTE)
message(STATUS "RabbitCommonUtils_ROOT:${RabbitCommonUtils_ROOT}")
set_property(GLOBAL PROPERTY RabbitCommonUtils_ROOT ${RabbitCommonUtils_ROOT})

include(CMakePackageConfigHelpers)
include(CMakeParseArguments)
include(GenerateExportHeader)
include(GNUInstallDirs)

# 产生android平台分发设置
# 详见： ${QT_INSTALL_DIR}/features/android/android_deployment_settings.prf
# ANDROID_SOURCES_DIR: Android 源码文件目录。默认为：${CMAKE_CURRENT_SOURCE_DIR}/android
function(GENERATED_DEPLOYMENT_SETTINGS)
    cmake_parse_arguments(PARA "" "NAME;APPLACTION;ANDROID_SOURCES_DIR" "" ${ARGN})

    if(NOT ANDROID_NDK)
        set(ANDROID_NDK $ENV{ANDROID_NDK})
        if(NOT ANDROID_NDK)
            set(ANDROID_NDK ${ANDROID_NDK_ROOT})
            if(NOT ANDROID_NDK)
                set(ANDROID_NDK $ENV{ANDROID_NDK_ROOT})
            endif()
        endif()
    endif()

    if(NOT ANDROID_SDK)
        set(ANDROID_SDK $ENV{ANDROID_SDK})
        if(NOT ANDROID_SDK)
            set(ANDROID_SDK ${ANDROID_SDK_ROOT})
            if(NOT ANDROID_SDK)
                set(ANDROID_SDK $ENV{ANDROID_SDK_ROOT})
            endif()
        endif()
    endif()

    if(NOT DEFINED BUILD_TOOS_VERSION)
        set(BUILD_TOOS_VERSION $ENV{BUILD_TOOS_VERSION})
    endif()
    if(NOT DEFINED BUILD_TOOS_VERSION)
        set(BUILD_TOOS_VERSION "28.0.3")
    endif()

    if(DEFINED PARA_NAME)
        set(_file_name ${PARA_NAME})
        #message("file_name:${PARA_NAME}")
    else()
        SET(_file_name "${PROJECT_BINARY_DIR}/android-lib${PROJECT_NAME}.so-deployment-settings.json")
    endif()

    FILE(WRITE ${_file_name} "{\n")
    FILE(APPEND ${_file_name} "\"description\": \"This file is generated by qmake to be read by androiddeployqt and should not be modified by hand.\",\n")
    FILE(APPEND ${_file_name} "\"qt\":\"${QT_INSTALL_DIR}\",\n")
    FILE(APPEND ${_file_name} "\"sdk\":\"${ANDROID_SDK}\",\n")
    FILE(APPEND ${_file_name} "\"sdkBuildToolsRevision\":\"${BUILD_TOOS_VERSION}\",\n")
    FILE(APPEND ${_file_name} "\"ndk\":\"${ANDROID_NDK}\",\n")

    FILE(APPEND ${_file_name} "\"stdcpp-path\":\"${ANDROID_NDK}/sources/cxx-stl/llvm-libc++/libs/${ANDROID_ABI}/libc++_shared.so\",\n")
    FILE(APPEND ${_file_name} "\"useLLVM\":true,\n")
    FILE(APPEND ${_file_name} "\"toolchain-prefix\":\"llvm\",\n")
    FILE(APPEND ${_file_name} "\"tool-prefix\":\"llvm\",\n")

    IF(CMAKE_HOST_WIN32)
        IF(ANDROID_NDK_HOST_X64)
            FILE(APPEND ${_file_name} "\"ndk-host\":\"windows-x86_64\",\n")
        ELSE()
            FILE(APPEND ${_file_name} "\"ndk-host\":\"windows\",\n")
        ENDIF()
    ELSE()
        IF(ANDROID_NDK_HOST_X64)
            FILE(APPEND ${_file_name} "\"ndk-host\":\"linux-x86_64\",\n")
	ELSE()
	    FILE(APPEND ${_file_name} "\"ndk-host\":\"linux\",\n")
        ENDIF()
    ENDIF()
    FILE(APPEND ${_file_name} "\"target-architecture\":\"${CMAKE_ANDROID_ARCH_ABI}\",\n")
    IF(DEFINED PARA_ANDROID_SOURCES_DIR)
        FILE(APPEND ${_file_name} "\"android-package-source-directory\":\"${PARA_ANDROID_SOURCES_DIR}\",\n")
    else()
        FILE(APPEND ${_file_name} "\"android-package-source-directory\":\"${CMAKE_CURRENT_SOURCE_DIR}/android\",\n")
    endif()
    IF(ANDROID_EXTRA_LIBS)
        FILE(APPEND ${_file_name} "\"android-extra-libs\":\"${ANDROID_EXTRA_LIBS}\",\n")
    ENDIF(ANDROID_EXTRA_LIBS)
    if(DEFINED PARA_APPLACTION)
        FILE(APPEND ${_file_name} "\"application-binary\":\"${PARA_APPLACTION}\"\n")
        #message("app_bin:${PARA_APPLACTION}")
    else()
        FILE(APPEND ${_file_name} "\"application-binary\":\"${CMAKE_BINARY_DIR}/bin/lib${PROJECT_NAME}.so\"\n")
    endif()
    FILE(APPEND ${_file_name} "}")
endfunction(GENERATED_DEPLOYMENT_SETTINGS)

# 得到子目录
macro(SUBDIRLIST result curdir)
    file(GLOB children RELATIVE ${curdir} ${curdir}/*)
    set(dirlist "")
    foreach(child ${children})
        if(IS_DIRECTORY ${curdir}/${child})
            LIST(APPEND dirlist ${child})
        endif()
    endforeach()
    set(${result} ${dirlist})
endmacro()

# 得到 GIT 库的版本
# 输入参数：
#   SOURCE_DIR: 库的根目录。默认：${CMAKE_SOURCE_DIR}
# 输出参数：
#   OUT_VERSION: 版本号
#   OUT_REVISION: 版本修正号
#   OUT_TAG: 标签
# 参见：
#   语义化版本: https://semver.org/lang/zh-CN/
function(GET_VERSION)
    cmake_parse_arguments(PARA "MATCH_PATTEN" "SOURCE_DIR;OUT_VERSION;OUT_REVISION;OUT_TAG" "" ${ARGN})
    # Find Git Version Patch

    if(NOT DEFINED PARA_SOURCE_DIR)
        set(PARA_SOURCE_DIR "${CMAKE_SOURCE_DIR}")
    endif()

    if(NOT PARA_MATCH_PATTEN)
        set(PARA_MATCH_PATTEN "v*")
    endif()
    IF(EXISTS "${PARA_SOURCE_DIR}/.git")
        if(NOT GIT)
            SET(GIT $ENV{GIT})
        endif()
        if(NOT GIT)
            FIND_PROGRAM(GIT NAMES git git.exe git.cmd)
        endif()
        IF(GIT)
            EXECUTE_PROCESS(
                WORKING_DIRECTORY ${PARA_SOURCE_DIR}
                COMMAND ${GIT} describe --tags --match "${PARA_MATCH_PATTEN}"
                OUTPUT_VARIABLE _OUT_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE
            )
            EXECUTE_PROCESS(
                WORKING_DIRECTORY ${PARA_SOURCE_DIR}
                COMMAND ${GIT} rev-parse --short HEAD
                OUTPUT_VARIABLE _OUT_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE
            )
            EXECUTE_PROCESS(
                WORKING_DIRECTORY ${PARA_SOURCE_DIR}
                COMMAND ${GIT} describe --abbrev=0 --tags --match "${PARA_MATCH_PATTEN}"
                OUTPUT_VARIABLE _OUT_TAG OUTPUT_STRIP_TRAILING_WHITESPACE
            )
            IF(_OUT_TAG AND DEFINED PARA_OUT_TAG)
                string(REPLACE "v" "" _OUT_TAG ${_OUT_TAG})
                SET(${PARA_OUT_TAG} ${_OUT_TAG} PARENT_SCOPE)
            ENDIF()
            IF(NOT _OUT_VERSION)
                SET(_OUT_VERSION ${_OUT_REVISION})
            ENDIF()
            IF(DEFINED PARA_OUT_VERSION)
                string(REPLACE "v" "" _OUT_VERSION ${_OUT_VERSION})
                SET(${PARA_OUT_VERSION} ${_OUT_VERSION} PARENT_SCOPE)
            ENDIF()
            IF(DEFINED PARA_OUT_REVISION)
                SET(${PARA_OUT_REVISION} ${_OUT_REVISION} PARENT_SCOPE)
            ENDIF()
        ELSE()
            message(AUTHOR_WARNING "Git is not exist. please set the value GIT to git")
        ENDIF()
    ELSE()
        message(AUTHOR_WARNING "The is not git repository: ${PARA_SOURCE_DIR}")
    ENDIF()
endfunction()

option(RABBIT_ENABLE_INSTALL_TO_BUILD_PATH
    "Install to build path. It only needs to be used when it is first configured"
    ON)
# Install directory
#   TARGET: project name
#   SOURCES: [MUST] source folder
#   DESTINATION: destination folder. don't include CMAKE_INSTALL_PREFIX
#   COMPONENT: component
#   PARAMETERS: install(DIRECTORY ) other parameters.
# NOTE: If not TARGET, it must be after ADD_TARGET
# #与 INSTALL(DIRECTORY ...) 功能相似，android 安装到 assets
function(INSTALL_DIR)
    cmake_parse_arguments(PARA "" "TARGET;DESTINATION;COMPONENT" "SOURCES;PARAMETERS" ${ARGN})

    if(NOT PARA_SOURCES)
        message(FATAL_ERROR "Please set SOURCES\nUsage: INSTALL_DIR([TARGET ... ] SOURCES ... [DESTINATION ... ] [COMPONENT ...])")
    endif()
    if(NOT PARA_TARGET)
        if(NOT TARGET ${PROJECT_NAME})
            message(WARNING "Move the INSTALL_DIR(...) to the back of the add_executable(...) or add_library(...)")
        else()
            set(PARA_TARGET ${PROJECT_NAME})
        endif()
    endif()
    if(NOT PARA_COMPONENT)
        set(PARA_COMPONENT Runtime)
    endif()
    if(NOT PARA_DESTINATION)
        set(PARA_DESTINATION .)
    endif()

#    if(ANDROID AND (QT_VERSION_MAJOR GREATER 5))
#        list(APPEND CMAKE_ANDROID_ASSETS_DIRECTORIES ${PARA_SOURCES})
#        set_property(TARGET ${PARA_TARGET} APPEND PROPERTY
#            ANDROID_ASSETS_DIRECTORIES ${PARA_SOURCES})
#    endif()

    install(DIRECTORY ${PARA_SOURCES}
        DESTINATION ${PARA_DESTINATION}
            COMPONENT ${PARA_COMPONENT}
            ${PARA_PARAMETERS}
        )

    if(ANDROID)
        set(PARA_DESTINATION "assets/${PARA_DESTINATION}")
    endif()

    if(RABBIT_ENABLE_INSTALL_TO_BUILD_PATH OR ANDROID)
        file(COPY ${PARA_SOURCES} DESTINATION ${CMAKE_BINARY_DIR}/${PARA_DESTINATION})
#        add_custom_command(
#            TARGET ${PARA_TARGET} POST_BUILD
#            COMMAND ${CMAKE_COMMAND} -E echo "Copy directory ${PARA_SOURCES} to ${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
#            COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
#            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PARA_SOURCES} "${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
#            COMMENT "Copy directory ${PARA_SOURCES} to ${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
#            VERBATIM)
    endif()

endfunction()

# https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html#module:GNUInstallDirs
#与 INSTALL(FILES ...) 功能相似，android 安装到 assets
function(INSTALL_FILE)
    cmake_parse_arguments(PARA "" "TARGET;DESTINATION;COMPONENT" "SOURCES" ${ARGN})

    if(NOT PARA_SOURCES)
        message(FATAL_ERROR "Please set SOURCES\nUsage: INSTALL_FILE([TARGET ... ] SOURCES ... [DESTINATION ... ] [COMPONENT ...])")
    endif()
    if(NOT PARA_TARGET)
        if(NOT TARGET ${PROJECT_NAME})
            message(FATAL_ERROR "Move the INSTALL_FILE(...) to the back of the add_executable(...) or add_library(...)")
        else()
            set(PARA_TARGET ${PROJECT_NAME})
        endif()
    endif()
    if(NOT PARA_COMPONENT)
        set(PARA_COMPONENT Runtime)
    endif()
    if(NOT PARA_DESTINATION)
        set(PARA_DESTINATION .)
    endif()

#    if(ANDROID AND (QT_VERSION_MAJOR GREATER 5))
#        list(APPEND CMAKE_ANDROID_ASSETS_DIRECTORIES ${PARA_SOURCES})
#        set_property(TARGET ${PARA_TARGET} APPEND PROPERTY
#            CMAKE_ANDROID_ASSETS_DIRECTORIES ${PARA_SOURCES})
#        endif()

    install(FILES ${PARA_SOURCES}
        DESTINATION ${PARA_DESTINATION}
            COMPONENT ${PARA_COMPONENT})

    if(ANDROID)
        set(PARA_DESTINATION "assets/${PARA_DESTINATION}")
    endif()

    if(RABBIT_ENABLE_INSTALL_TO_BUILD_PATH OR ANDROID)
        #file(COPY ${PARA_SOURCES} DESTINATION ${CMAKE_BINARY_DIR}/${PARA_DESTINATION})
        add_custom_command(
            TARGET ${PARA_TARGET} PRE_BUILD
            COMMAND ${CMAKE_COMMAND} -E echo "Copy files ${PARA_SOURCES} to ${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
            COMMAND ${CMAKE_COMMAND} -E make_directory "${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
            COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PARA_SOURCES} "${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
            COMMENT "Copy directory ${PARA_SOURCES} to ${CMAKE_BINARY_DIR}/${PARA_DESTINATION}"
            COMMAND_EXPAND_LISTS
            VERBATIM)
    endif()

endfunction()

# Install QIcon theme
#   TARGET: project name
#   SOURCES: Default is ${CMAKE_CURRENT_SOURCE_DIR}/Resource/icons
#   DESTINATION: Default is share/icons
#   COMPONENT: component
#   PARAMETERS: install(DIRECTORY ) other parameters
# NOTE: If not TARGET, it must be after ADD_TARGET
function(INSTALL_ICON_THEME)
    cmake_parse_arguments(PARA "" "TARGET;DESTINATION;COMPONENT" "SOURCES;PARAMETERS" ${ARGN})

    if(NOT PARA_TARGET)
        if(NOT TARGET ${PROJECT_NAME})
            message(FATAL_ERROR "Move the INSTALL_ICON_THEME(...) to the back of the add_executable(...) or add_library(...)")
        else()
            set(PARA_TARGET ${PROJECT_NAME})
        endif()
    endif()

    if(NOT PARA_SOURCES)
        set(PARA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../Src/Resource/icons)
    endif()
    if(NOT PARA_COMPONENT)
        set(PARA_COMPONENT Runtime)
    endif()
    if(NOT PARA_DESTINATION)
        set(PARA_DESTINATION ${CMAKE_INSTALL_DATADIR})
    endif()
    INSTALL_DIR(TARGET ${PARA_TARGET}
        SOURCES ${PARA_SOURCES}
        DESTINATION ${PARA_DESTINATION}
        COMPONENT ${PARA_COMPONENT}
        PARAMETERS ${PARA_PARAMETERS}
    )
endfunction()

# Install style files
#   TARGET: project name
#   SOURCES: Default is ${CMAKE_CURRENT_SOURCE_DIR}/Resource/style
#   DESTINATION: Default is share/style
#   COMPONENT: component
# NOTE: If not TARGET, it must be after ADD_TARGET
function(INSTALL_STYLE)
    cmake_parse_arguments(PARA "" "TARGET;DESTINATION;COMPONENT" "SOURCES" ${ARGN})

    if(NOT PARA_TARGET)
        if(NOT TARGET ${PROJECT_NAME})
            message(FATAL_ERROR "Move the INSTALL_STYLE(...) to the back of the add_executable(...) or add_library(...)")
        else()
            set(PARA_TARGET ${PROJECT_NAME})
        endif()
    endif()

    if(NOT PARA_SOURCES)
        set(PARA_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/../Src/Resource/style)
    endif()
    if(NOT PARA_COMPONENT)
        set(PARA_COMPONENT Runtime)
    endif()
    if(NOT PARA_DESTINATION)
        set(PARA_DESTINATION ${CMAKE_INSTALL_DATADIR})
    endif()
    INSTALL_DIR(TARGET ${PARA_TARGET}
        SOURCES ${PARA_SOURCES}
        DESTINATION ${PARA_DESTINATION}
            COMPONENT ${PARA_COMPONENT})
endfunction()

# 安装指定目标文件
# [必须]TARGETS      需要安装的目标
# [必须]DESTINATION  安装的位置
# [可选]COMPONENT    组件
option(RABBIT_ENABLE_INSTALL_TARGETS
    "Enable install the targets. It only needs to be used when it is first configured"
    OFF)
function(INSTALL_TARGETS)
    cmake_parse_arguments(PARA "" "DESTINATION;COMPONENT" "TARGETS" ${ARGN})
    if(NOT DEFINED PARA_TARGETS)
        message(FATAL_ERROR "Usage: INSTALL_TARGETS(TARGETS ... DESTINATION ... [COMPONENT ...])")
    endif()

    if(NOT RABBIT_ENABLE_INSTALL_TARGETS)
        return()
    endif()
    if(NOT DEFINED PARA_DESTINATION)
        if(ANDROID)
            set(PARA_DESTINATION "libs/${ANDROID_ABI}")
        elseif(WIN32)
            set(PARA_DESTINATION "${CMAKE_INSTALL_BINDIR}")
        else()
            set(PARA_DESTINATION "${CMAKE_INSTALL_LIBDIR}")
        endif()
    endif()
    
    if(NOT DEFINED PARA_COMPONENT)
        set(PARA_COMPONENT DependLibraries)
    endif()

    foreach(component ${PARA_TARGETS})
        # if(RABBIT_ENABLE_INSTALL_TO_BUILD_PATH)
        #     if(WIN32)
        #         set(BUILD_PATH ${CMAKE_BINARY_DIR}/bin)
        #     else()
        #         set(BUILD_PATH ${CMAKE_BINARY_DIR}/lib)
        #     endif()
        #     add_custom_command(
        #         TARGET ${component} POST_BUILD
        #         COMMAND ${CMAKE_COMMAND} -E echo "Copy files ${PARA_SOURCES} to ${BUILD_PATH}"
        #         COMMAND ${CMAKE_COMMAND} -E make_directory "${BUILD_PATH}"
        #         COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:${component}> "${BUILD_PATH}"
        #         COMPONENT ${PARA_COMPONENT}
        #         COMMAND_EXPAND_LISTS
        #         VERBATIM)
        # endif()
        INSTALL(FILES $<TARGET_FILE:${component}>
            DESTINATION "${PARA_DESTINATION}"
                COMPONENT ${PARA_COMPONENT})
        IF((NOT ANDROID) AND UNIX)
            INSTALL(FILES $<TARGET_SONAME_FILE:${component}>
                DESTINATION "${PARA_DESTINATION}"
                    COMPONENT ${PARA_COMPONENT})
        ENDIF()
    endforeach()
endfunction()

# Install dependencies runtime dlls
option(RABBIT_ENABLE_INSTALL_DEPENDENT
    "Enable install dependent runtime dlls"
    OFF
)

option(RABBIT_ENABLE_INSTALL_QT
    "Install qt libraries. It only needs to be used when it is first configured."
    ON
)

# 安装目标
#    [必须]NAME                  目标名
#    ISEXE                      是执行程序目标还是库目标
#    ISPLUGIN                   是插件
#    IS_MACOSX_BUNDLE           安装 MACOSX BUNDLE 目录
#    RUNTIME                    执行程序安装位置
#    LIBRARY                    库安装位置
#    INSTALL_PLUGIN_LIBRARY_DIR 插件库安装位置
#    ARCHIVE
#    PUBLIC_HEADER              头文件的安装位置
#    INCLUDES                   导出安装头文件位置
#    VERSION                    版本号
#    EXPORT_NAME                cmake 配置文件的导出名
#    NAMESPACE                  cmake 配置文件的导出目录
#    COMPONENT                  组件名。
#       - 如果未定义。
#         - 运行库组件名为： Runtime
#         - 开发库组件名为： Development
#         - 应用程序组件名为： Appliatoin
#         - 插件组件名为： Plugin
#         - Qt 依赖库组件名为： DependLibraries
#    COMPONENT_PREFIX       组件名前缀。
#       - 如果定义。
#         - 运行库组件名为： ${COMPONENT_PREFIX}
#         - 开发库组件名为： ${COMPONENT_PREFIX}Development
#         - 应用程序组件名为： ${COMPONENT_PREFIX}Appliatoin
#         - 插件组件名为： ${COMPONENT_PREFIX}Plugin
#         - Qt 依赖库组件名为： ${COMPONENT_PREFIX}DependLibraries
#    INSTALL_CMAKE_CONFIG_IN_FILE   ${PROJECT_NAME}Config.cmake.in 位置
function(INSTALL_TARGET)
    SET(SINGLE_PARAS
        NAME
        EXPORT_NAME
        NAMESPACE
        RUNTIME
        LIBRARY
        ARCHIVE
        PUBLIC_HEADER
        INSTALL_PLUGIN_LIBRARY_DIR
        VERSION
        COMPONENT
        COMPONENT_PREFIX
        INSTALL_CMAKE_CONFIG_IN_FILE
        )
    cmake_parse_arguments(PARA "ISEXE;ISPLUGIN;IS_MACOSX_BUNDLE"
        "${SINGLE_PARAS}"
        "INCLUDES"
        ${ARGN})
    if(NOT DEFINED PARA_NAME)
        message(FATAL_ERROR "Usage:
            INSTALL_TARGET
                NAME name
                [ISEXE]
                [ISPULGIN]
                [IS_MACOSX_BUNDLE]
                [INSTALL_PLUGIN_LIBRARY_DIR ...]
                [RUNTIME ...]
                [LIBRARY ...]
                [ARCHIVE ...]
                [PUBLIC_HEADER ...]
                [INCLUDES ...]
                [VERSION version]
                [EXPORT_NAME install export configure file name]
                [COMPONENT ...]
                [COMPONENT_PREFIX ...]
                [INSTALL_CMAKE_CONFIG_IN_FILE cmake configure(Config.cmake.in) file]"
                )
    endif()
    if(NOT DEFINED PARA_COMPONENT)
        set(PARA_COMPONENT_DEV ${PARA_COMPONENT_PREFIX}Development)
        set(PARA_COMPONENT_DEPEND_LIBRARY ${PARA_COMPONENT_PREFIX}DependLibraries)
    else()
        set(PARA_COMPONENT_DEV ${PARA_COMPONENT})
        set(PARA_COMPONENT_DEPEND_LIBRARY ${PARA_COMPONENT})
    endif()

    # cmake >= 3.16, the CMAKE_INSTALL_LIBDIR is support multi-arch lib dir
    # See: https://gitlab.kitware.com/cmake/cmake/-/issues/20565
    # See: [GNUInstallDirs](https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html#module:GNUInstallDirs)
    # Install target
    if(APPLE)
        if(NOT DEFINED PARA_RUNTIME)
            if(PARA_IS_MACOSX_BUNDLE)
                set(PARA_RUNTIME ".")
            else()
                set(PARA_RUNTIME "MacOS")
            endif()
        endif()
        if(NOT DEFINED PARA_LIBRARY)
            set(PARA_LIBRARY "FrameWorks")
        endif()
    elseif(ANDROID)
        if(NOT DEFINED PARA_RUNTIME)
            set(PARA_RUNTIME "libs/${ANDROID_ABI}")
        endif()
        if(NOT DEFINED PARA_LIBRARY)
            set(PARA_LIBRARY "libs/${ANDROID_ABI}")
        endif()
    elseif(WIN32)
        if(NOT DEFINED PARA_RUNTIME)
            set(PARA_RUNTIME "${CMAKE_INSTALL_BINDIR}")
        endif()
        if(NOT DEFINED PARA_LIBRARY)
            set(PARA_LIBRARY "${CMAKE_INSTALL_BINDIR}")
        endif()
    else()
        if(NOT DEFINED PARA_RUNTIME)
            set(PARA_RUNTIME "${CMAKE_INSTALL_BINDIR}")
        endif()
        if(NOT DEFINED PARA_LIBRARY)
            set(PARA_LIBRARY "${CMAKE_INSTALL_LIBDIR}")
        endif()
    endif()
    if(NOT DEFINED PARA_ARCHIVE)
        set(PARA_ARCHIVE "${CMAKE_INSTALL_LIBDIR}")
    endif()

    if(PARA_ISPLUGIN)

        if(NOT DEFINED PARA_COMPONENT)
            set(PARA_COMPONENT ${PARA_COMPONENT_PREFIX}Plugin)
        endif()

        if(APPLE)
            INSTALL(TARGETS ${PARA_NAME}
                LIBRARY DESTINATION "${PARA_INSTALL_PLUGIN_LIBRARY_DIR}"
                        COMPONENT ${PARA_COMPONENT}
                )
        elseif(WIN32)
            INSTALL(TARGETS ${PARA_NAME}
                RUNTIME DESTINATION "${PARA_INSTALL_PLUGIN_LIBRARY_DIR}"
                        COMPONENT ${PARA_COMPONENT}
                )
        elseif(ANDROID)
            # cmake >= 3.16, the CMAKE_INSTALL_LIBDIR is support multi-arch lib dir
            # See: https://gitlab.kitware.com/cmake/cmake/-/issues/20565
            INSTALL(TARGETS ${PARA_NAME}
                LIBRARY DESTINATION "libs/${ANDROID_ABI}"
                        COMPONENT ${PARA_COMPONENT}
                )
        else()
            INSTALL(TARGETS ${PARA_NAME}
                LIBRARY DESTINATION "${PARA_INSTALL_PLUGIN_LIBRARY_DIR}"
                        COMPONENT ${PARA_COMPONENT}
                )
        endif()

    else(PARA_ISPLUGIN) # Is not plugin

        if(PARA_ISEXE)

            if(NOT DEFINED PARA_COMPONENT)
                set(PARA_COMPONENT ${PARA_COMPONENT_PREFIX}Application)
            endif()

            if(RABBIT_ENABLE_INSTALL_DEPENDENT)
                set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION "${PARA_RUNTIME}")
                set(CMAKE_INSTALL_SYSTEM_RUNTIME_COMPONENT ${PARA_COMPONENT})
                set(CMAKE_INSTALL_UCRT_LIBRARIES TRUE)
                include(InstallRequiredSystemLibraries)
            endif()

            option(RABBIT_WITH_MACDEPLOY "With macdeploy deploy" ON)
            if(RABBIT_WITH_MACDEPLOY AND APPLE)
                # See: https://doc.qt.io/qt-6/macos-deployment.html
                find_program(MACDEPLOYQT_EXECUTABLE macdeployqt
                    HINTS ${QT_INSTALL_DIR}/bin
                    DOC "Path to macdeployqt executable"
                )
                if(MACDEPLOYQT_EXECUTABLE)
                    message("Find macdeployqt: ${MACDEPLOYQT_EXECUTABLE}")
                else()
                    message(FATAL_ERROR "Don't find macdeployqt in ${QT_INSTALL_DIR}/bin")
                endif()
            endif()
            # MACOSX_BUNDLE
            if(PARA_IS_MACOSX_BUNDLE AND APPLE)
                INSTALL(TARGETS ${PARA_NAME}
                    BUNDLE DESTINATION .
                        COMPONENT ${PARA_COMPONENT}
                    )

                if(RABBIT_WITH_MACDEPLOY)
                    # 将变量值直接嵌入到代码字符串中
                    string(CONFIGURE [[
                        message(STATUS "Copy directory to $<TARGET_BUNDLE_DIR_NAME:@PARA_NAME@>/Contents ......")
                        file(COPY "$<INSTALL_PREFIX>/"
                            DESTINATION "$<INSTALL_PREFIX>/$<TARGET_BUNDLE_DIR_NAME:@PARA_NAME@>/Contents"
                            PATTERN $<TARGET_BUNDLE_DIR_NAME:@PARA_NAME@> EXCLUDE)
                        ]] copy_dir_string @ONLY)
                    INSTALL(CODE ${copy_dir_string}
                            COMPONENT ${PARA_COMPONENT}
                    )
                    # Create dmg file
                    string(CONFIGURE [[
                        message(STATUS "Execute macdeployqt to deploy @PARA_NAME@.app ......")
                        execute_process(COMMAND @MACDEPLOYQT_EXECUTABLE@ "$<INSTALL_PREFIX>/@PARA_NAME@.app" -dmg -verbose=3)
                        ]] macdeploy_string @ONLY
                    )
                    INSTALL(CODE ${macdeploy_string}
                            COMPONENT ${PARA_COMPONENT}
                    )
                endif()
            else() # NOT MACOSX_BUNDLE
                INSTALL(TARGETS ${PARA_NAME}
                    RUNTIME DESTINATION "${PARA_RUNTIME}"
                        COMPONENT ${PARA_COMPONENT}
                    )

                if(APPLE)
                    # 使用正则表达式检查结尾
                    if("${CMAKE_INSTALL_PREFIX}" MATCHES "Contents$")
                        if(RABBIT_WITH_MACDEPLOY)
                            # Create dmg file
                            string(CONFIGURE [[
                                message(STATUS "Execute macdeployqt to deploy @PARA_NAME@.app ......")
                                execute_process(COMMAND @MACDEPLOYQT_EXECUTABLE@ "$<INSTALL_PREFIX>/.." -dmg -verbose=3)
                                ]] macdeploy_string @ONLY
                                )
                            INSTALL(CODE ${macdeploy_string}
                                COMPONENT ${PARA_COMPONENT}
                            )
                        endif()
                    else()
                        message(WARNING "The CMAKE_INSTALL_PREFIX is not in BUNDLE directory format. It is recommended to use: ${CMAKE_INSTALL_PREFIX}/${PARA_NAME}/Contents")
                    endif()
                endif()
            endif()

            #分发
            IF( ANDROID AND (QT_VERSION_MAJOR VERSION_LESS 6) )
                if( (NOT PARA_ANDROID_SOURCES_DIR)
                        AND (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/android) )
                    set(PARA_ANDROID_SOURCES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android)
                endif()
                Set(JSON_FILE ${CMAKE_BINARY_DIR}/android_deployment_settings.json)
                GENERATED_DEPLOYMENT_SETTINGS(NAME ${JSON_FILE}
                    ANDROID_SOURCES_DIR ${PARA_ANDROID_SOURCES_DIR}
                    APPLACTION "${CMAKE_BINARY_DIR}/bin/lib${PARA_NAME}.so")

                if(CMAKE_BUILD_TYPE)
                    string(TOLOWER ${CMAKE_BUILD_TYPE} LOWER_BUILD_TYPE)
                endif()
                if(LOWER_BUILD_TYPE STREQUAL "release")
                    if(NOT DEFINED STOREPASS)
                        set(STOREPASS $ENV{STOREPASS})
                    endif()

                    if(STOREPASS)
                        add_custom_target(APK_${PARA_NAME} #注意 需要把 ${QT_INSTALL_DIR}/bin 加到环境变量PATH中
                            COMMAND "${QT_INSTALL_DIR}/bin/androiddeployqt"
                                --output ${CMAKE_INSTALL_PREFIX} #注意输出文件名为：[${CMAKE_INSTALL_PREFIX}的最后一级目录名]-release-signed.apk
                                --input ${JSON_FILE}
                                --verbose
                                --gradle
                                --release
                                --android-platform ${ANDROID_PLATFORM}
                                --sign ${RabbitCommon_ROOT}/RabbitCommon.keystore rabbitcommon
                                --storepass ${STOREPASS}
                            )
                    else()
                        message(WARNING "Please set camke parameter or environment value STOREPASS, will use debug deploy ......")
                        add_custom_target(APK_${PARA_NAME} #注意 需要把 ${QT_INSTALL_DIR}/bin 加到环境变量PATH中
                            COMMAND "${QT_INSTALL_DIR}/bin/androiddeployqt"
                                --output ${CMAKE_INSTALL_PREFIX} #注意输出文件名为：[${CMAKE_INSTALL_PREFIX}的最后一级目录名]-debug.apk
                                --input ${JSON_FILE}
                                --verbose
                                --gradle
                                --android-platform ${ANDROID_PLATFORM}
                            )
                    endif()

                else()
                    add_custom_target(APK_${PARA_NAME} #注意 需要把 ${QT_INSTALL_DIR}/bin 加到环境变量PATH中
                        COMMAND "${QT_INSTALL_DIR}/bin/androiddeployqt"
                            --output ${CMAKE_INSTALL_PREFIX} #注意输出文件名为：[${CMAKE_INSTALL_PREFIX}的最后一级目录名]-debug.apk
                            --input ${JSON_FILE}
                            --verbose
                            --gradle
                            --android-platform ${ANDROID_PLATFORM}
                        )
                    add_custom_target(INSTALL_APK_${PARA_NAME} #注意 需要把 ${QT_INSTALL_DIR}/bin 加到环境变量PATH中
                        COMMAND "${QT_INSTALL_DIR}/bin/androiddeployqt"
                            --output ${CMAKE_INSTALL_PREFIX} #注意输出文件名为：[${CMAKE_INSTALL_PREFIX}的最后一级目录名]-debug.apk
                            --input ${JSON_FILE}
                            --reinstall
                            --verbose
                            --gradle
                            --android-platform ${ANDROID_PLATFORM}
                        )
                endif()

            ENDIF() # ANDROID AND QT_VERSION_MAJOR VERSION_LESS 6

        else(PARA_ISEXE) # Is library

            if(NOT DEFINED PARA_PUBLIC_HEADER)
                set(PARA_PUBLIC_HEADER ${CMAKE_INSTALL_INCLUDEDIR}/${PARA_NAME})
            endif()
            if(NOT DEFINED PARA_INCLUDES)
                set(PARA_INCLUDES ${CMAKE_INSTALL_INCLUDEDIR}
                    ${CMAKE_INSTALL_INCLUDEDIR}/${PARA_NAME}
                    )
            endif()

            if(NOT DEFINED PARA_EXPORT_NAME)
                set(PARA_EXPORT_NAME ${PARA_NAME}Config)
            endif()
            if(NOT DEFINED PARA_COMPONENT)
                set(PARA_COMPONENT ${PARA_COMPONENT_PREFIX}Runtime)
            endif()

            INSTALL(TARGETS ${PARA_NAME}
                EXPORT ${PARA_EXPORT_NAME}
                RUNTIME DESTINATION "${PARA_RUNTIME}"
                    COMPONENT ${PARA_COMPONENT}
                LIBRARY DESTINATION "${PARA_LIBRARY}"
                    COMPONENT ${PARA_COMPONENT}
                ARCHIVE DESTINATION "${PARA_ARCHIVE}"
                    COMPONENT ${PARA_COMPONENT_DEV}
                PUBLIC_HEADER DESTINATION ${PARA_PUBLIC_HEADER}
                    COMPONENT ${PARA_COMPONENT_DEV}
                INCLUDES DESTINATION ${PARA_INCLUDES}
                )
            # Install cmake configure files
            if(DEFINED PARA_NAMESPACE)
                #export(TARGETS ${PARA_NAME}
                #    APPEND FILE ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}Config.cmake
                #    NAMESPACE ${PARA_NAMESPACE}::
                #    )
                install(EXPORT ${PARA_EXPORT_NAME}
                    DESTINATION "${PARA_ARCHIVE}/cmake/${PARA_NAMESPACE}"
                        COMPONENT ${PARA_COMPONENT_DEV}
                    NAMESPACE ${PARA_NAMESPACE}::
                    )
            else()
                set(PARA_NAMESPACE ${PARA_NAME})
                #export(TARGETS ${PARA_NAME}
                #    APPEND FILE ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}Config.cmake
                #    )
                # Install cmake configure files
                install(EXPORT ${PARA_EXPORT_NAME}
                    DESTINATION "${PARA_ARCHIVE}/cmake/${PARA_NAMESPACE}"
                        COMPONENT ${PARA_COMPONENT_DEV}
                    )
            endif()
            if(NOT (PARA_EXPORT_NAME STREQUAL ${PARA_NAME}Config) )
                # 因为编译树中已有 export(${PARA_NAME}Config.cmake)
                if(NOT DEFINED PARA_INSTALL_CMAKE_CONFIG_IN_FILE)
                    set(PARA_INSTALL_CMAKE_CONFIG_IN_FILE ${CMAKE_SOURCE_DIR}/cmake/${PARA_NAME}Config.cmake.in)
                endif()
                if(EXISTS ${PARA_INSTALL_CMAKE_CONFIG_IN_FILE})
                    configure_package_config_file(
                        ${PARA_INSTALL_CMAKE_CONFIG_IN_FILE}
                        ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}Config.cmake.in
                        INSTALL_DESTINATION "${PARA_ARCHIVE}/cmake/${PARA_NAMESPACE}"
                        )
                    install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}Config.cmake.in
                        DESTINATION "${PARA_ARCHIVE}/cmake/${PARA_NAMESPACE}"
                            COMPONENT ${PARA_COMPONENT_DEV}
                        RENAME ${PARA_NAME}Config.cmake)
                else()
                    message(WARNING "Please create file: ${PARA_INSTALL_CMAKE_CONFIG_IN_FILE}")
                endif()
            endif()
            # Install cmake version configure file
            if(NOT DEFINED PARA_VERSION)
                get_target_property(PARA_VERSION ${PARA_NAME} VERSION)
            endif()
            if(PARA_VERSION)
                string(REPLACE "v" "" PARA_VERSION ${PARA_VERSION})
                write_basic_package_version_file(
                    "${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}ConfigVersion.cmake"
                    VERSION ${PARA_VERSION}
                    COMPATIBILITY AnyNewerVersion)
                install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}ConfigVersion.cmake"
                    DESTINATION "${PARA_ARCHIVE}/cmake/${PARA_NAMESPACE}"
                    COMPONENT ${PARA_COMPONENT_DEV})
            endif()

            # Install pkg-config file
            if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}.pc)
                install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}.pc"
                    DESTINATION "${PARA_ARCHIVE}/pkgconfig"
                    COMPONENT ${PARA_COMPONENT_DEV})
            endif()
        endif(PARA_ISEXE)
    endif(PARA_ISPLUGIN)

    if(RABBIT_ENABLE_INSTALL_DEPENDENT AND (NOT ANDROID))
        install(FILES $<TARGET_RUNTIME_DLLS:${PARA_NAME}>
            DESTINATION "${PARA_LIBRARY}"
                COMPONENT ${PARA_COMPONENT_DEPEND_LIBRARY})
    endif()

    # Windows 下分发
    IF(WIN32 AND (BUILD_SHARED_LIBS OR PARA_ISEXE)
        AND (RABBIT_ENABLE_INSTALL_DEPENDENT OR RABBIT_ENABLE_INSTALL_QT))

        find_program(WINDEPLOYQT_EXECUTABLE windeployqt
            HINTS ${QT_INSTALL_DIR}/bin
            DOC "Path to windeployqt executable"
        )
        if(WINDEPLOYQT_EXECUTABLE)
            message("find windeployqt: ${WINDEPLOYQT_EXECUTABLE}")
        else()
            message(WARNING "Don't find windeployqt in ${QT_INSTALL_DIR}/bin")
        endif()
        IF(MINGW)
            if(QT_VERSION_MAJOR VERSION_LESS 6)
                # windeployqt 分发时，是根据是否 strip 来判断是否是 DEBUG 版本,而用 mingw 编译时,qt 没有自动 strip
                add_custom_command(TARGET ${PARA_NAME} POST_BUILD
                    COMMAND strip "$<TARGET_FILE:${PARA_NAME}>"
                    )
                # #注意 需要把 ${QT_INSTALL_DIR}/bin 加到环境变量PATH中
                # add_custom_command(TARGET ${PARA_NAME} POST_BUILD
                #     COMMAND ${CMAKE_COMMAND} -E echo "Exec windeployqt for ${PARA_NAME}"
                #     COMMAND "${WINDEPLOYQT_EXECUTABLE}"
                #         #--compiler-runtime # 因为已用了 include(InstallRequiredSystemLibraries)
                #         --verbose 7
                #         --no-quick-import
                #         --dir "${CMAKE_BINARY_DIR}/DependLibraries"
                #         --libdir "${CMAKE_BINARY_DIR}/DependLibraries"
                #         --plugindir "${CMAKE_BINARY_DIR}/DependLibraries"
                #         "$<TARGET_FILE:${PARA_NAME}>"
                #     )
                string(CONFIGURE [[
                    message(STATUS "Exec windeployqt for @PARA_NAME@ ......")
                    execute_process(
                        COMMAND "@WINDEPLOYQT_EXECUTABLE@"
                            #--compiler-runtime # 因为已用了 include(InstallRequiredSystemLibraries)
                            --verbose 7
                            --no-quick-import
                            --dir "@CMAKE_BINARY_DIR@/DependLibraries"
                            --libdir "@CMAKE_BINARY_DIR@/DependLibraries"
                            --plugindir "@CMAKE_BINARY_DIR@/DependLibraries"
                            "$<TARGET_FILE:@PARA_NAME@>"
                    )
                    ]] code_windeployqt @ONLY)
                INSTALL(CODE ${code_windeployqt}
                    COMPONENT ${PARA_COMPONENT_DEPEND_LIBRARY}
                )
            endif()
        ELSE(MINGW)
            # #注意 需要把 ${QT_INSTALL_DIR}/bin 加到环境变量PATH中
            # add_custom_command(TARGET ${PARA_NAME} POST_BUILD
            #     COMMAND ${CMAKE_COMMAND} -E echo "Exec windeployqt for ${PARA_NAME}"
            #     COMMAND "${WINDEPLOYQT_EXECUTABLE}"
            #         #--compiler-runtime # 因为已用了 include(InstallRequiredSystemLibraries)
            #         --verbose 7
            #         --no-quick-import
            #         --dir "${CMAKE_BINARY_DIR}/DependLibraries"
            #         --libdir "${CMAKE_BINARY_DIR}/DependLibraries"
            #         --plugindir "${CMAKE_BINARY_DIR}/DependLibraries"
            #         "$<TARGET_FILE:${PARA_NAME}>"
            #     )
            string(CONFIGURE [[
                message(STATUS "Exec windeployqt for @PARA_NAME@ ......")
                execute_process(
                    COMMAND "@WINDEPLOYQT_EXECUTABLE@"
                        #--compiler-runtime # 因为已用了 include(InstallRequiredSystemLibraries)
                        --verbose 7
                        --no-quick-import
                        --dir "@CMAKE_BINARY_DIR@/DependLibraries"
                        --libdir "@CMAKE_BINARY_DIR@/DependLibraries"
                        --plugindir "@CMAKE_BINARY_DIR@/DependLibraries"
                        "$<TARGET_FILE:@PARA_NAME@>"
                )
                ]] code_windeployqt @ONLY)
            INSTALL(CODE ${code_windeployqt}
                COMPONENT ${PARA_COMPONENT_DEPEND_LIBRARY}
            )
        ENDIF(MINGW)

        if(PARA_ISEXE AND RABBIT_ENABLE_INSTALL_QT)
            INSTALL(DIRECTORY "${CMAKE_BINARY_DIR}/DependLibraries/"
                DESTINATION "${PARA_LIBRARY}"
                COMPONENT ${PARA_COMPONENT_DEPEND_LIBRARY})
        endif()
    ENDIF()
endfunction()

# 增加目标
# 注意：在调用之前，需要 include(GenerateExportHeader)
# 参数：
#    [必须]SOURCE_FILES              源文件（包括头文件，资源文件等）
#    ISEXE                          是执行程序目标还是库目标
#    ISPLUGIN                       是插件
#    NO_TRANSLATION                 不产生翻译资源
#    ISWINDOWS                      窗口程序
#    IS_MACOSX_BUNDLE               产生 MACOSX BUNDLE 目录
#    NAME                           目标名。注意：翻译资源文件名(.ts)默认是 ${PROJECT_NAME}
#    OUTPUT_DIR                     目标生成目录
#    VERSION                        版本
#    SOVERSION
#    ANDROID_SOURCES_DIR            Android 源码文件目录
#    INCLUDE_DIRS                   包含目录
#    PRIVATE_INCLUDE_DIRS           私有包含目录
#    LIBS                           公有依赖库
#    PRIVATE_LIBS                   私有依赖库
#    LINK_DIRECTORIES               连接目录
#    PRIVATE_LINK_DIRECTORIES       私有连接目录
#    DEFINITIONS                    公有宏定义
#    PRIVATE_DEFINITIONS            私有宏宏义
#    OPTIONS                        公有选项
#    PRIVATE_OPTIONS                私有选项
#    FEATURES                       公有特性
#    PRIVATE_FEATURES               私有特性
#    NO_INSTALL_ANDROID_OPENSSL     当是 android 时，不安装 openssl 库
#    QT_ANDROID_EXTRA_LIBS          Android 外部库
#    NO_INSTALL                     不安装
#    INSTALL_RPATH                  INSTALL_RPATH
#    INSTALL_HEADER_FILES           如果是库，要安装的头文件
#    INSTALL_PUBLIC_HEADER          头文件安装位置
#    INSTALL_INCLUDES               导出安装头文件位置
#    INSTALL_PLUGIN_LIBRARY_DIR     库安装位置
#    INSTALL_EXPORT_NAME            安装 CMAKE 配置文件导出名
#    INSTALL_NAMESPACE              安装 cmake 配置文件的导出目录 
#    INSTALL_CMAKE_CONFIG_IN_FILE   安装 ${PROJECT_NAME}Config.cmake.in 位置
#    COMPONENT              组件名。
#       - 如果未定义。
#         - 运行库组件名为： Runtime
#         - 开发库组件名为： Development
#         - 应用程序组件名为： Appliatoin
#         - 插件组件名为： Plugin
#         - Qt 依赖库组件名为： DependLibraries
#    COMPONENT_PREFIX       组件名前缀。
#       - 如果定义。
#         - 运行库组件名为： ${COMPONENT_PREFIX}
#         - 开发库组件名为： ${COMPONENT_PREFIX}Development
#         - 应用程序组件名为： ${COMPONENT_PREFIX}Appliatoin
#         - 插件组件名为： ${COMPONENT_PREFIX}Plugin
#         - Qt 依赖库组件名为： ${COMPONENT_PREFIX}DependLibraries
function(ADD_TARGET)
    SET(MUT_PARAS
        SOURCE_FILES             #源文件（包括头文件，资源文件等）
        INSTALL_HEADER_FILES     #如果是库，要安装的头文件
        INCLUDE_DIRS             #包含目录
        PRIVATE_INCLUDE_DIRS     #私有包含目录
        LIBS                     #公有依赖库
        PRIVATE_LIBS             #私有依赖库
        LINK_DIRECTORIES         #连接目录
        PRIVATE_LINK_DIRECTORIES #私有连接目录
        DEFINITIONS              #公有宏定义
        PRIVATE_DEFINITIONS      #私有宏宏义
        OPTIONS                  #公有选项
        PRIVATE_OPTIONS          #私有选项
        FEATURES                 #公有特性
        PRIVATE_FEATURES         #私有特性
        INSTALL_INCLUDES         #导出包安装的头文件目录
        QT_ANDROID_EXTRA_LIBS    #Android 外部库
        )
    SET(SINGLE_PARAS
        NAME
        OUTPUT_DIR
        VERSION
        SOVERSION
        INSTALL_RPATH
        ANDROID_SOURCES_DIR
        INSTALL_PUBLIC_HEADER
        INSTALL_PLUGIN_LIBRARY_DIR
        INSTALL_EXPORT_NAME
        INSTALL_NAMESPACE
        INSTALL_CMAKE_CONFIG_IN_FILE
        COMPONENT
        COMPONENT_PREFIX
        )
    cmake_parse_arguments(PARA
        "ISEXE;ISPLUGIN;ISWINDOWS;IS_MACOSX_BUNDLE;NO_TRANSLATION;NO_INSTALL;NO_INSTALL_ANDROID_OPENSSL"
        "${SINGLE_PARAS}"
        "${MUT_PARAS}"
        ${ARGN})
    if(NOT DEFINED PARA_SOURCE_FILES)
        message(FATAL_ERROR "Usage:
            ADD_TARGET
                [NAME name]
                [ISEXE]
                [ISPLUGIN]
                [ISWINDOWS]
                [IS_MACOSX_BUNDLE]
                [NO_TRANSLATION]
                [NO_INSTALL]
                [NO_INSTALL_ANDROID_OPENSSL]
                SOURCE_FILES source1 [source2 ... header1 ...]]
                [INSTALL_HEADER_FILES header1 [header2 ...]]
                [LIBS lib1 [lib2 ...]]
                [PRIVATE_LIBS lib1 [lib2 ...]]
                [LINK_DIRECTORIES dir1 [dir2 ...]]
                [PRIVATE_LINK_DIRECTORIES dir1 [dir2 ...]]
                [INCLUDE_DIRS [include_dir1 ...]]
                [PRIVATE_INCLUDE_DIRS [include_dir1 ...]]
                [DEFINITIONS [definition1 ...]]
                [PRIVATE_DEFINITIONS [defnitions1 ...]]
                [OUTPUT_DIR output_dir]
                [PRIVATE_OPTIONS option1 [option2 ...]]
                [OPTIONS option1 [option2 ...]]
                [FEATURES feature1 [feature2 ...]]
                [PRIVATE_FEATURES feature1 [feature2 ...]]
                [VERSION version]
                [SOVERSION soversion]
                [INSTALL_RPATH install_rpath]
                [ANDROID_SOURCES_DIR android_source_dir]
                [INSTALL_PLUGIN_LIBRARY_DIR dir]
                [INSTALL_EXPORT_NAME configure_file_name]
                [INSTALL_CMAKE_CONFIG_IN_FILE install cmake config file]
                [COMPONENT ...]
                [COMPONENT_PREFIX ...]")
        return()
    endif()

    if(NOT DEFINED PARA_NAME)
        if(NOT PROJECT_NAME)
            message(FATAL_ERROR "Move the ADD_TARGET(...) to the back of the project(...)")
        endif()
        set(PARA_NAME ${PROJECT_NAME})
    endif()

    if(NOT PARA_NO_TRANSLATION)
        #翻译资源
        if(PARA_ISPLUGIN)
            set(QM_INSTALL_DIR ${PARA_INSTALL_PLUGIN_LIBRARY_DIR}/translations)
        else()
            set(QM_INSTALL_DIR ${CMAKE_INSTALL_DATADIR}/translations)
        endif()

        if(NOT DEFINED PARA_COMPONENT)
            if(PARA_ISEXE)
                set(TRANSLATIONS_COMPONENT ${PARA_COMPONENT_PREFIX}Application)
            elseif(PARA_ISPLUGIN)
                set(TRANSLATIONS_COMPONENT ${PARA_COMPONENT_PREFIX}Plugin)
            else()
                set(TRANSLATIONS_COMPONENT ${PARA_COMPONENT_PREFIX}Runtime)
            endif()
        else()
                set(TRANSLATIONS_COMPONENT ${PARA_COMPONENT})
        endif()

        GENERATED_QT_TRANSLATIONS(
            ALL
            TARGET ${PARA_NAME}
            SOURCES ${PARA_SOURCE_FILES} ${PARA_INSTALL_HEADER_FILES}
            OUT_QRC TRANSLATIONS_QRC_FILES
            QM_INSTALL_DIR ${QM_INSTALL_DIR}
            INSTALL_COMPONENT ${TRANSLATIONS_COMPONENT}
        )
        #TODO: 非优雅的方法
        if(CMAKE_BUILD_TYPE)
            string(TOLOWER ${CMAKE_BUILD_TYPE} LOWER_BUILD_TYPE)
        endif()
        if(LOWER_BUILD_TYPE STREQUAL "debug")
            LIST(APPEND PARA_SOURCE_FILES ${TRANSLATIONS_QRC_FILES})
        endif()
    endif(NOT PARA_NO_TRANSLATION)

    if(PARA_ISEXE)

        if(ANDROID)
            if(QT_VERSION_MAJOR GREATER_EQUAL 6)
                qt_add_executable(${PARA_NAME} ${PARA_SOURCE_FILES}
                    ${PARA_INSTALL_HEADER_FILES})
            else()
                add_library(${PARA_NAME} SHARED ${PARA_SOURCE_FILES} ${PARA_INSTALL_HEADER_FILES})
            endif()
            if( (NOT PARA_ANDROID_SOURCES_DIR)
                    AND (IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/android) )
                set(PARA_ANDROID_SOURCES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android)
            endif()
            if(PARA_ANDROID_SOURCES_DIR)
                if(QT_VERSION_MAJOR GREATER_EQUAL 6)
                    set_property(TARGET ${PARA_NAME} APPEND PROPERTY
                        QT_ANDROID_PACKAGE_SOURCE_DIR ${PARA_ANDROID_SOURCES_DIR})
                else()
                    set(ANDROID_PACKAGE_SOURCE_DIR ${PARA_ANDROID_SOURCES_DIR})
                endif()
            endif()

            if (NOT PARA_NO_INSTALL_ANDROID_OPENSSL)
                include(FetchContent)
                FetchContent_Declare(
                    android_openssl
                    DOWNLOAD_EXTRACT_TIMESTAMP true
                    URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip
                )
                FetchContent_MakeAvailable(android_openssl)
                include(${android_openssl_SOURCE_DIR}/android_openssl.cmake)
                get_target_property(VAR_QT_ANDROID_EXTRA_LIBS ${PARA_NAME} QT_ANDROID_EXTRA_LIBS)
                SET(PARA_QT_ANDROID_EXTRA_LIBS
                    ${PARA_QT_ANDROID_EXTRA_LIBS} ${VAR_QT_ANDROID_EXTRA_LIBS})
                add_android_openssl_libraries(${PROJECT_NAME})
            endif()

            if(PARA_QT_ANDROID_EXTRA_LIBS)
                get_target_property(VAR_QT_ANDROID_EXTRA_LIBS ${PARA_NAME} QT_ANDROID_EXTRA_LIBS)
                SET(PARA_QT_ANDROID_EXTRA_LIBS
                    ${PARA_QT_ANDROID_EXTRA_LIBS} ${VAR_QT_ANDROID_EXTRA_LIBS})
                set_target_properties(${PARA_NAME} PROPERTIES
                    QT_ANDROID_EXTRA_LIBS ${PARA_QT_ANDROID_EXTRA_LIBS})
            endif()

            # NOTE: 如果不用 ADD_TARGET 时，请手动安装.参见：INSTALL_DIR，INSTALL_FILE
#                file(COPY ${CMAKE_BINARY_DIR}/assets
#                    DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/android-build/)
            add_custom_command(
                TARGET ${PARA_NAME} POST_BUILD
                COMMAND ${CMAKE_COMMAND} -E echo "copy directory ${CMAKE_BINARY_DIR}/assets to ${CMAKE_CURRENT_BINARY_DIR}/android-build/assets"
                COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_BINARY_DIR}/assets" "${CMAKE_CURRENT_BINARY_DIR}/android-build/assets"
                COMMENT "Copy directory ${CMAKE_BINARY_DIR}/assets/ to ${CMAKE_CURRENT_BINARY_DIR}/android-build/assets"
                COMMAND_EXPAND_LISTS
                VERBATIM)

        else() # NO ANDROID

            if(PARA_ISWINDOWS AND WIN32)
                set(WINDOWS_APP WIN32)
            endif()
            if(QT_VERSION_MAJOR GREATER_EQUAL 6)
                qt_add_executable(${PARA_NAME} ${WINDOWS_APP} ${PARA_SOURCE_FILES} ${PARA_INSTALL_HEADER_FILES})
            else()
                add_executable(${PARA_NAME} ${WINDOWS_APP} ${PARA_SOURCE_FILES} ${PARA_INSTALL_HEADER_FILES})
            endif()

            if(MINGW)
                set_target_properties(${PARA_NAME} PROPERTIES LINK_FLAGS "-mwindows")
            elseif(MSVC)
                # 程序以windows方式启动，不出现控制台窗口
                if(Qt5_VERSION VERSION_LESS "5.7.0")
                    set_target_properties(${PARA_NAME} PROPERTIES LINK_FLAGS
                        "/SUBSYSTEM:WINDOWS\",5.01\" /ENTRY:mainCRTStartup")
                else()
                    set_target_properties(${PARA_NAME} PROPERTIES LINK_FLAGS
                        "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup")
                endif()
            endif()

            if(WIN32)
                set_target_properties(${PARA_NAME} PROPERTIES
                    WIN32_EXECUTABLE TRUE)
            endif()
            if(PARA_IS_MACOSX_BUNDLE AND APPLE)
                set_target_properties(${PARA_NAME} PROPERTIES MACOSX_BUNDLE TRUE)
            endif()

        endif()

    else(PARA_ISEXE) # Is library

        # For debug libs and exes, add "_d" postfix
        if(NOT CMAKE_DEBUG_POSTFIX)
            set(CMAKE_DEBUG_POSTFIX "_d")
        endif()
        if(CMAKE_BUILD_TYPE)
            string(TOLOWER ${CMAKE_BUILD_TYPE} LOWER_BUILD_TYPE)
        endif()
        if(LOWER_BUILD_TYPE STREQUAL "debug")
            set(PC_POSTIX ${CMAKE_DEBUG_POSTFIX})
        endif()
        if(WIN32)
            if(LOWER_BUILD_TYPE STREQUAL "debug")
                option(RABBIT_WITH_LIBRARY_SUFFIX_VERSION "Library suffix plus version number" OFF)
            else()
                option(RABBIT_WITH_LIBRARY_SUFFIX_VERSION "Library suffix plus version number" ON)
            endif()
            if(RABBIT_WITH_LIBRARY_SUFFIX_VERSION)
                if(NOT PARA_VERSION)
                    get_target_property(PARA_VERSION ${PARA_NAME} VERSION)
                    if(NOT PARA_VERSION)
                        message(AUTHOR_WARNING "The VERSION is null, When the target(${PARA_NAME}). please set it the VERSION of ADD_TARGET.")
                    endif()
                endif()
                if(PARA_VERSION_FOUND OR PARA_VERSION)
                    if(CMAKE_BUILD_TYPE)
                        string(TOUPPER ${CMAKE_BUILD_TYPE} UPPER_CMAKE_BUILD_TYPE)
                        SET(CMAKE_${UPPER_CMAKE_BUILD_TYPE}_POSTFIX "${CMAKE_${UPPER_CMAKE_BUILD_TYPE}_POSTFIX}_${PARA_VERSION}")
                        set(PC_POSTIX ${CMAKE_${UPPER_CMAKE_BUILD_TYPE}_POSTFIX})
                    elseif(CMAKE_CONFIGURATION_TYPES)
                        foreach(PARA_CONFIG ${CMAKE_CONFIGURATION_TYPES})
                            string(TOUPPER ${PARA_CONFIG} UPPER_PARA_CONFIG)
                            SET(CMAKE_${UPPER_PARA_CONFIG}_POSTFIX "${CMAKE_${UPPER_PARA_CONFIG}_POSTFIX}_${PARA_VERSION}")
                            set(PC_POSTIX ${CMAKE_${UPPER_CMAKE_BUILD_TYPE}_POSTFIX})
                        endforeach()
                    endif()
                endif(PARA_VERSION_FOUND OR PARA_VERSION)
            endif(RABBIT_WITH_LIBRARY_SUFFIX_VERSION)
        endif()

        string(TOLOWER ${PARA_NAME} LOWER_PROJECT_NAME)
        set(PARA_INSTALL_HEADER_FILES ${PARA_INSTALL_HEADER_FILES} 
            ${CMAKE_CURRENT_BINARY_DIR}/${LOWER_PROJECT_NAME}_export.h)

        if(QT_VERSION_MAJOR GREATER_EQUAL 6)
            qt_add_library(${PARA_NAME} ${PARA_SOURCE_FILES} ${PARA_INSTALL_HEADER_FILES})
        else()
            add_library(${PARA_NAME} ${PARA_SOURCE_FILES} ${PARA_INSTALL_HEADER_FILES})
        endif()

        GENERATE_EXPORT_HEADER(${PARA_NAME})
        file(COPY ${CMAKE_CURRENT_BINARY_DIR}/${LOWER_PROJECT_NAME}_export.h
            DESTINATION ${CMAKE_BINARY_DIR})

        # Generate pkg-config file
        set(PC_DEFINITIONS)
        foreach(d ${PARA_DEFINITIONS})
            SET(PC_DEFINITIONS "${PC_DEFINITIONS} -D${d}")
        endforeach()
        if(NOT RabbitCommon_ROOT)
            set(RabbitCommon_ROOT ${RabbitCommon_ROOT})
        endif()
        if(RabbitCommon_ROOT)
            set(PC_FILE ${RabbitCommon_ROOT}/cmake/RabbitCommon.pc.in)
        else()
            get_property(PARA_RabbitCommonUtils_ROOT GLOBAL PROPERTY RabbitCommonUtils_ROOT)
            set(PC_FILE ${PARA_RabbitCommonUtils_ROOT}/RabbitCommon.pc.in)
        endif()
        if(EXISTS ${PC_FILE})
            configure_file(${PC_FILE}
                ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}.pc @ONLY)
            message("Generate pkg-config file: ${PC_FILE} to ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}.pc")
        endif()

    endif(PARA_ISEXE)

    if(NOT PARA_INSTALL_RPATH)
        # https://cmake.org/cmake/help/v3.26/prop_tgt/INSTALL_RPATH.html#prop_tgt:INSTALL_RPATH
        # setup rpath to where binary is at.
        if(APPLE)
            if(PARA_ISEXE)
                SET(PARA_INSTALL_RPATH
                    "@executable_path/../Frameworks")
            elseif(PARA_ISPLUGIN)
                SET(PARA_INSTALL_RPATH
                    "@loader_path")
            else()
                SET(PARA_INSTALL_RPATH
                    "@loader_path/../Frameworks")
            endif()
            # See: https://cmake.org/cmake/help/v3.15/prop_tgt/MACOSX_RPATH.html#prop_tgt:MACOSX_RPATH
            SET_TARGET_PROPERTIES(${PARA_NAME}
                PROPERTIES MACOSX_RPATH ON)
        else()
            SET(PARA_INSTALL_RPATH
                "$ORIGIN:$ORIGIN/../${CMAKE_INSTALL_LIBDIR}")
        endif()
    endif()
    # setup rpath to where binary is at.
    SET_TARGET_PROPERTIES(${PARA_NAME}
        PROPERTIES INSTALL_RPATH
            ${PARA_INSTALL_RPATH})
    # 如果为 TRUE ,编译时直接使用安装时的动态连接为搜索路径
    # Use RPATHs from build tree _in_ the build tree
    #set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
    # 如果为 TRUE ,把构建时的链接路径加到 INSTALL_RPATH 之后
    # Do not add default linker search paths to RPATH
    #set(CMAKE_INSTALL_RPATH_USE_LINK_PATH FALSE)

    if(DEFINED PARA_OUTPUT_DIR)
        set_target_properties(${PARA_NAME} PROPERTIES
            LIBRARY_OUTPUT_DIRECTORY ${PARA_OUTPUT_DIR}
            RUNTIME_OUTPUT_DIRECTORY ${PARA_OUTPUT_DIR}
            ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
        )
    else()
        if(APPLE)
            if(PARA_IS_MACOSX_BUNDLE)
                set_target_properties(${PARA_NAME} PROPERTIES
                    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/.)
            else()
                set_target_properties(${PARA_NAME} PROPERTIES
                    RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/MacOS)
            endif()
            set_target_properties(${PARA_NAME} PROPERTIES
                ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
                LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/FrameWorks
                )
        elseif(NOT (ANDROID AND (QT_VERSION_MAJOR GREATER_EQUAL 6)))
            set_target_properties(${PARA_NAME} PROPERTIES
                RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
                ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
                )
            if(WIN32)
                set_target_properties(${PARA_NAME} PROPERTIES
                    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin
                )
            else()
                set_target_properties(${PARA_NAME} PROPERTIES
                    LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib
                )
            endif()
        endif()
    endif()

    # Be will to install header files
    if(DEFINED PARA_INSTALL_HEADER_FILES)
        set_target_properties(${PARA_NAME} PROPERTIES
            PUBLIC_HEADER "${PARA_INSTALL_HEADER_FILES}" # Install head files
            )
    endif()

    if(NOT PARA_VERSION)
        set(PARA_VERSION ${PROJECT_VERSION})
    endif()
    if(PARA_VERSION)
        string(REPLACE "v" "" PARA_VERSION ${PARA_VERSION})
        if(WIN32)
            string(FIND ${PARA_VERSION} "-" _VERSION_GIT_POS)
            string(SUBSTRING ${PARA_VERSION} 0 ${_VERSION_GIT_POS} PARA_MSVC_VERSION)
            string(REPLACE "." "," PARA_MSVC_VERSION ${PARA_MSVC_VERSION})
            if(NOT(PARA_MSVC_VERSION MATCHES "[0-9]+\,[0-9]+\,[0-9]+"))
                set(PARA_MSVC_VERSION "0,0,0")
            endif()
        endif()

        if(NOT PARA_SOVERSION)
            string(FIND ${PARA_VERSION} "." _VERSION_MAJOR_POS)
            string(SUBSTRING ${PARA_VERSION} 0 ${_VERSION_MAJOR_POS} PARA_SOVERSION)
        endif()
        string(REPLACE "v" "" PARA_SOVERSION ${PARA_SOVERSION})
        set_target_properties(${PARA_NAME} PROPERTIES
            VERSION ${PARA_VERSION}
        )
        if(MSVC)
            get_property(PARA_RabbitCommonUtils_ROOT GLOBAL PROPERTY RabbitCommonUtils_ROOT)
            if(RabbitCommon_ROOT)
                set(VERSION_RC_FILE ${RabbitCommon_ROOT}/cmake/Version.rc.in)
            else()
                set(VERSION_RC_FILE ${PARA_RabbitCommonUtils_ROOT}/Version.rc.in)
            endif()
            configure_file("${VERSION_RC_FILE}"
                           ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}_Version.rc)
            target_sources(${PARA_NAME} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/${PARA_NAME}_Version.rc)
        endif()
    else()
        message(AUTHOR_WARNING "Please set VERSION in project(${PARA_NAME})")
    endif()

    if(PARA_SOVERSION)
        set_target_properties(${PARA_NAME} PROPERTIES
            SOVERSION ${PARA_SOVERSION}
        )
    endif()

    if(DEFINED PARA_LIBS AND PARA_LIBS)
        target_link_libraries(${PARA_NAME} PUBLIC ${PARA_LIBS})
    endif()

    if(DEFINED PARA_PRIVATE_LIBS AND PARA_PRIVATE_LIBS)
        target_link_libraries(${PARA_NAME} PRIVATE ${PARA_PRIVATE_LIBS})
    endif()

    if(PARA_LINK_DIRECTORIES)
        target_link_directories(${PARA_NAME} PRIVATE ${PARA_LINK_DIRECTORIES})
    endif()
    
    if(PARA_PRIVATE_LINK_DIRECTORIES)
        target_link_directories(${PARA_NAME} PRIVATE ${PARA_PRIVATE_LINK_DIRECTORIES})
    endif()

    # Target compile definitions
    target_compile_definitions(${PARA_NAME} PRIVATE
        $<$<CONFIG:Debug>:_DEBUG DEBUG>
        )
    if(DEFINED PARA_DEFINITIONS)
        target_compile_definitions(${PARA_NAME} PUBLIC ${PARA_DEFINITIONS})
    endif()
    if(DEFINED PARA_PRIVATE_DEFINITIONS AND PARA_PRIVATE_DEFINITIONS)
        target_compile_definitions(${PARA_NAME} PRIVATE ${PARA_PRIVATE_DEFINITIONS})
    endif()

    # Target include directories
    if(DEFINED PARA_INCLUDE_DIRS AND PARA_INCLUDE_DIRS)
        target_include_directories(${PARA_NAME} PUBLIC ${PARA_INCLUDE_DIRS})
    endif()
    if(DEFINED PARA_PRIVATE_INCLUDE_DIRS AND PARA_PRIVATE_INCLUDE_DIRS)
        target_include_directories(${PARA_NAME} PRIVATE ${PARA_PRIVATE_INCLUDE_DIRS})
    endif()

    # Target compile options
    IF(MSVC)
        # This option is to enable the /MP switch for Visual Studio 2005 and above compilers
        OPTION(RABBIT_WIN32_USE_MP "Set to ON to build with the /MP option (Visual Studio 2005 and above)." ON)
        MARK_AS_ADVANCED(RABBIT_WIN32_USE_MP)
        IF(RABBIT_WIN32_USE_MP)
            target_compile_options(${PARA_NAME} PRIVATE /MP)
        ENDIF(RABBIT_WIN32_USE_MP)
    ENDIF(MSVC)
    target_compile_options(${PARA_NAME} PRIVATE
        "$<$<C_COMPILER_ID:MSVC>:/utf-8>"
        "$<$<CXX_COMPILER_ID:MSVC>:/utf-8>"
        $<$<CXX_COMPILER_ID:GNU,Clang>:$<IF:$<CONFIG:Debug>, -g -ggdb, -O3>>)
    if(NOT MINGW)
        target_compile_options(${PARA_NAME} PRIVATE
            $<$<CXX_COMPILER_ID:GNU,Clang>:-fPIC>
        )
    endif()
    if(DEFINED PARA_OPTIONS)
        target_compile_options(${PARA_NAME} PUBLIC ${PARA_OPTIONS})
    endif()
    if(DEFINED PARA_PRIVATE_OPTIONS)
        target_compile_options(${PARA_NAME} PRIVATE ${PARA_PRIVATE_OPTIONS})
    endif()

    # Target compile features
    if(DEFINED PARA_FEATURES)
        target_compile_features(${PARA_NAME} PUBLIC ${PARA_FEATURES})
    endif()

    if(DEFINED PARA_PRIVATE_FEATURES)
        target_compile_features(${PARA_NAME} PRIVATE ${PARA_PRIVATE_FEATURES})
    endif()

    # 因为只会复制直接依赖。不会复制间接依赖。所以，只复制了Qt库，而不会复制平台插件。所以导致以下错误：
    #  This application failed to start because no Qt platform plugin could be initialized. Reinstalling the application may fix this problem.
    #
    # Copy the target's dependent dynamic library
    #if(RABBIT_ENABLE_INSTALL_TO_BUILD_PATH AND RABBIT_ENABLE_INSTALL_DEPENDENT)
    #    add_custom_command(TARGET ${PARA_NAME} POST_BUILD
    #        COMMAND ${CMAKE_COMMAND} -E echo "Copy ${PARA_NAME}'s dependent dynamic library $<TARGET_RUNTIME_DLLS:${PARA_NAME}>"
    #        COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_RUNTIME_DLLS:${PARA_NAME}> $<TARGET_FILE:${PARA_NAME}> $<TARGET_FILE_DIR:${PARA_NAME}>
    #        COMMAND_EXPAND_LISTS
    #        VERBATIM
    #    )
    #endif()

    if(NOT PARA_NO_INSTALL)
        # Install target
        if(PARA_ISPLUGIN)
            INSTALL_TARGET(NAME ${PARA_NAME}
                ISPLUGIN
                PUBLIC_HEADER ${PARA_INSTALL_PUBLIC_HEADER}
                INCLUDES ${PARA_INSTALL_INCLUDES}
                INSTALL_PLUGIN_LIBRARY_DIR ${PARA_INSTALL_PLUGIN_LIBRARY_DIR}
                COMPONENT ${PARA_COMPONENT}
                COMPONENT_PREFIX ${PARA_COMPONENT_PREFIX}
                VERSION ${PARA_VERSION}
            )
        elseif(PARA_ISEXE)

            if(NOT ANDROID)
                if(PARA_IS_MACOSX_BUNDLE)
                    set(_HAS_PARAS IS_MACOSX_BUNDLE)
                endif()
                INSTALL_TARGET(NAME ${PARA_NAME}
                    ISEXE
                    ${_HAS_PARAS}
                    PUBLIC_HEADER ${PARA_INSTALL_PUBLIC_HEADER}
                    INCLUDES ${PARA_INSTALL_INCLUDES}
                    COMPONENT ${PARA_COMPONENT}
                    COMPONENT_PREFIX ${PARA_COMPONENT_PREFIX}
                    VERSION ${PARA_VERSION})
            endif()

        else() # Is library

            INSTALL_TARGET(NAME ${PARA_NAME}
                EXPORT_NAME ${PARA_INSTALL_EXPORT_NAME}
                NAMESPACE ${PARA_INSTALL_NAMESPACE}
                PUBLIC_HEADER ${PARA_INSTALL_PUBLIC_HEADER}
                INCLUDES ${PARA_INSTALL_INCLUDES}
                COMPONENT ${PARA_COMPONENT}
                COMPONENT_PREFIX ${PARA_COMPONENT_PREFIX}
                INSTALL_CMAKE_CONFIG_IN_FILE ${PARA_INSTALL_CMAKE_CONFIG_IN_FILE}
                VERSION ${PARA_VERSION})

        endif()
    endif()
endfunction()

# 增加插件目标
# 参数：
#  NAME                    目标名
#  OUTPUT_DIR              目标生成目录
#  VERSION                 版本
#  SOVERSION
#  INSTALL_RPATH
#  ANDROID_SOURCES_DIR     Android 源码文件目录
#  [必须]SOURCE_FILES       源文件（包括头文件，资源文件等）
#  INCLUDE_DIRS            包含目录
#  PRIVATE_INCLUDE_DIRS    私有包含目录
#  LIBS                    公有依赖库
#  PRIVATE_LIBS            私有依赖库
#  LINK_DIRECTORIES               连接目录
#  PRIVATE_LINK_DIRECTORIES       私有连接目录
#  DEFINITIONS             公有宏定义
#  PRIVATE_DEFINITIONS     私有宏宏义
#  OPTIONS                 公有选项
#  PRIVATE_OPTIONS         私有选项
#  FEATURES                公有特性
#  PRIVATE_FEATURES        私有特性
#  INSTALL_DIR             插件库安装目录，默认：plugins 。
#                          注意：只接受相对路径。绝对路径时，翻译资源前缀会有问题。
#  NO_TRANSLATION          不产生翻译资源
function(ADD_PLUGIN_TARGET)
    SET(MUT_PARAS
        SOURCE_FILES            #源文件（包括头文件，资源文件等）
        INCLUDE_DIRS            #包含目录
        PRIVATE_INCLUDE_DIRS    #私有包含目录
        LIBS                    #公有依赖库
        PRIVATE_LIBS            #私有依赖库
        LINK_DIRECTORIES         #连接目录
        PRIVATE_LINK_DIRECTORIES #私有连接目录
        DEFINITIONS             #公有宏定义
        PRIVATE_DEFINITIONS     #私有宏宏义
        OPTIONS                 #公有选项
        PRIVATE_OPTIONS         #私有选项
        FEATURES                #公有特性
        PRIVATE_FEATURES        #私有特性
        )
    cmake_parse_arguments(PARA "NO_TRANSLATION"
        "NAME;OUTPUT_DIR;VERSION;SOVERSION;INSTALL_RPATH;ANDROID_SOURCES_DIR;INSTALL_DIR"
        "${MUT_PARAS}"
        ${ARGN})
    if(NOT DEFINED PARA_SOURCE_FILES)
        message(FATAL_ERROR "Usage:
            ADD_TARGET
                [NAME name]
                SOURCE_FILES source1 [source2 ... header1 ...]]
                [LIBS lib1 [lib2 ...]]
                [PRIVATE_LIBS lib1 [lib2 ...]]
                [LINK_DIRECTORIES dir1 [dir2 ...]]
                [PRIVATE_LINK_DIRECTORIES dir1 [dir2 ...]]
                [INCLUDE_DIRS [include_dir1 ...]]
                [PRIVATE_INCLUDE_DIRS [include_dir1 ...]]
                [DEFINITIONS [definition1 ...]]
                [PRIVATE_DEFINITIONS [defnitions1 ...]]
                [OUTPUT_DIR output_dir]
                [PRIVATE_OPTIONS option1 [option2 ...]]
                [OPTIONS option1 [option2 ...]]
                [FEATURES feature1 [feature2 ...]]
                [PRIVATE_FEATURES feature1 [feature2 ...]]
                [VERSION version]
                [SOVERSION soversion]
                [INSTALL_RPATH install_rpath]
                [ANDROID_SOURCES_DIR android_source_dir]")
        return()
    endif()

    if(NOT DEFINED PARA_OUTPUT_DIR)
        set(PARA_OUTPUT_DIR ${CMAKE_BINARY_DIR}/plugins)
    endif()

    if(NOT DEFINED PARA_INSTALL_DIR)
        set(PARA_INSTALL_DIR plugins)
    endif()

    if(PARA_NO_TRANSLATION)
        set(PARA_NO_TRANSLATION NO_TRANSLATION)
    endif()
    ADD_TARGET(NAME ${PARA_NAME}
        ISPLUGIN
        ${PARA_NO_TRANSLATION}
        OUTPUT_DIR ${PARA_OUTPUT_DIR}
        VERSION ${PARA_VERSION}
        INSTALL_RPATH ${PARA_INSTALL_RPATH}
        ANDROID_SOURCES_DIR ${PARA_ANDROID_SOURCES_DIR}
        SOURCE_FILES ${PARA_SOURCE_FILES}
        LIBS ${PARA_LIBS}
        PRIVATE_LIBS ${PARA_PRIVATE_LIBS}
        LINK_DIRECTORIES ${PRIVATE_LINK_DIRECTORIES}
        PRIVATE_LINK_DIRECTORIES ${PARA_PRIVATE_LINK_DIRECTORIES}
        DEFINITIONS ${PARA_DEFINITIONS}
        PRIVATE_DEFINITIONS ${PARA_PRIVATE_DEFINITIONS}
        OPTIONS ${PARA_OPTIONS}
        PRIVATE_OPTIONS ${PARA_PRIVATE_OPTIONS}
        FEATURES ${FEATURES}
        PRIVATE_FEATURES ${PRIVATE_FEATURES}
        PRIVATE_INCLUDE_DIRS ${PARA_PRIVATE_INCLUDE_DIRS}
        INSTALL_PLUGIN_LIBRARY_DIR ${PARA_INSTALL_DIR}
        )
endfunction()

message(STATUS "RABBIT_ENABLE_INSTALL_TO_BUILD_PATH:${RABBIT_ENABLE_INSTALL_TO_BUILD_PATH}")
message(STATUS "RABBIT_ENABLE_INSTALL_DEPENDENT:${RABBIT_ENABLE_INSTALL_DEPENDENT}")
message(STATUS "RABBIT_ENABLE_INSTALL_QT:${RABBIT_ENABLE_INSTALL_QT}")
message(STATUS "RABBIT_ENABLE_INSTALL_TARGETS:${RABBIT_ENABLE_INSTALL_TARGETS}")
message(STATUS "RABBIT_WITH_LIBRARY_SUFFIX_VERSION:${RABBIT_WITH_LIBRARY_SUFFIX_VERSION}")
message(STATUS "RABBIT_WIN32_USE_MP:${RABBIT_WIN32_USE_MP}")
